﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dIRca.Data;

namespace dIRca.Network
{
    public class RecipientService
    {
        private bool _isProperlNamed;
        private Channel _realChannel;

        public IMessagesView StatusLog { get; private set; }
        public List<IMessagesView> Channels { get; private set; }

        public string ServerName { get; set; }
        public string NickName { get; set; }

        public event EventHandler<RecipientEventArgs> ChannelAdded;
        public event EventHandler<RecipientEventArgs> ChannelRemoved;
        public event EventHandler<RefreshMessagesEventArgs> RefreshMessages;

        public RecipientService()
        {
            StatusLog = new StatusLog() { Name = "Status", Messages = new List<Message>(), };
            Channels = new List<IMessagesView>();
            _realChannel = new Channel();
        }

        public void Add(Message record)
        {
            var channelName = record.WindowName;
            if (channelName.ToLower() == "status")
            {
                if (string.IsNullOrEmpty(record.NickName))
                    record.NickName = ServerName;
                StatusLog.Messages.Add(record);
                OnRefreshMessages(channelName);
                return;
            }
            var intendedChannel = (from c in Channels
                                   where c.Name.ToLower() == channelName.ToLower()
                                   select c).FirstOrDefault();
            if (intendedChannel == null)
            {
                RecipientInitialize(ref _realChannel, record);
                return;
            }
            if (ParseRecipient(intendedChannel, record))
            {
                intendedChannel.Messages.Add(record);
                OnRefreshMessages(intendedChannel.Name);
            }
        }

        public void RemoveChannel(string channelName)
        {
            var intendedChannel = (from c in Channels
                                   where c.Name.ToLower() == channelName.ToLower()
                                   select c).FirstOrDefault();
            if (intendedChannel != null)
            {
                Channels.Remove(intendedChannel);
                OnChannelRemoved(intendedChannel);
            }
        }

        void RecipientInitialize(ref Channel recipient, Message record)
        {
            // Two entry points (at least in the UI):
            // Join -> Topic -> Name (* x)->EndOfNames
            // Topic -> Name (* x)->EndOfNames-> Join
            // Parse Join, Topic, and Names commands to fill in Channel data
            if (record.ReceiveType == ReceiveType.Join)
            {
                recipient.Name = record.WindowName;
                _isProperlNamed = true;
            }
            if (record.ReceiveType == ReceiveType.Topic || record.ReceiveType == ReceiveType.TopicChange)
            {
                recipient.Name = _isProperlNamed ? recipient.Name : record.WindowName;
                recipient.Topic = record.MessageData;
            }
            // Inspect the message for Names start (usually on channel join)
            if (record.ReceiveType == ReceiveType.Name && record.ReplyCode == ReplyCode.NamesReply)
            {
                recipient.Name = _isProperlNamed ? recipient.Name : record.WindowName;
                recipient.NickNames.AddRange(ParseNickNames(record.MessageData));
            }
            if (record.ReceiveType == ReceiveType.Name && record.ReplyCode == ReplyCode.EndOfNames)
            {
                // Wrap it up, B!
                if (_isProperlNamed)
                {
                    Channels.Add(recipient);
                    OnChannelAdded(recipient);
                    _isProperlNamed = false;
                    recipient = new Channel();
                }
            }
        }

        bool ParseRecipient(IMessagesView recipient, Message record)
        {
            var result = true;
            if (record.ReceiveType == ReceiveType.Join)
            {
                if (NickName != record.NickName)
                {
                    AddNickName(recipient as Channel, record.NickName);
                    OnRefreshMessages(recipient.Name);
                    result = false;
                }
            }

            // Issue #30 Channel parts
            if (record.ReceiveType == ReceiveType.Part)
            {
                if (NickName == record.NickName)
                {
                    RemoveChannel(recipient.Name);
                    OnChannelRemoved(recipient);
                }
                else
                {
                    RemoveNickName(recipient as Channel, record.NickName);
                    OnRefreshMessages(recipient.Name);
                }
                result = false;
            }

            // Issue #29 Channel NickNames
            if (record.ReceiveType == ReceiveType.NickChange)
            {
                if (NickName != record.NickName)
                {
                    ChangeNickName(recipient as Channel, record.NickName, record.MessageData);
                    result = false;
                }
            }

            return result;
        }

        IEnumerable<string> ParseNickNames(string message)
        {
            return message.Split(' ').Where(x => !string.IsNullOrEmpty(x));
        }

        void RemoveNickName(Channel recipient, string nickName)
        {
            if (recipient.NickNames.Contains(nickName))
                recipient.NickNames.Remove(nickName);
        }

        void AddNickName(Channel recipient, string nickName)
        {
            if (!recipient.NickNames.Contains(nickName))
                recipient.NickNames.Add(nickName);
        }

        void ChangeNickName(Channel recipient, string oldNickName, string newNickName)
        {
            var index = recipient.NickNames.IndexOf(oldNickName);
            if (index > -1)
            {
                recipient.NickNames.RemoveAt(index);
                recipient.NickNames.Add(newNickName);
            }
        }

        void OnChannelAdded(IMessagesView recipient)
        {
            var handler = ChannelAdded;
            if (handler != null)
                handler(this, new RecipientEventArgs() { Recipient = recipient });
        }

        void OnChannelRemoved(IMessagesView recipient)
        {
            var handler = ChannelRemoved;
            if (handler != null)
                handler(this, new RecipientEventArgs() { Recipient = recipient });
        }

        void OnRefreshMessages(string e)
        {
            var handler = RefreshMessages;
            if (handler != null)
                handler(this, new RefreshMessagesEventArgs() { Name = e });
        }
    }
}
